import * as THREE from "three";
import * as $ from "jquery";

import { OBJECTS, FLAGS } from "./declarations";
import { TOOLS } from "./tools/tools";
import TweenMax from "gsap/TweenMaxBase";
import { CONFIG } from "./config";

let actors, materials, groups, lights, textures , car_follow , prevTime;

let road, car, self, delta; 

let driveCurrentSpeed,
  driveAccelerationRate,
  driveMaxSpeed,
  driveDeccelerationRate,
  driveMinSpeed;

let position = new THREE.Vector3();
const binormal = new THREE.Vector3();
const direction = new THREE.Vector3(0, 0, 0);
const car_LookAt = new THREE.Vector3(0, 1, 0);
const cam_rear_LookAt = new THREE.Vector3(0, 1, 0);

const normal = new THREE.Vector3();
const lookAhead = true;

//

let progress_car = 0 + 0.01 // car must be ahead of the chase camera // 车的初始位置
let progress_cam_rear = 0.008; // 车后方摄像头的初始位置

window.$ = $;

let DRIVE = {
  accelerate: false,
  ready: false,
  // delta: OBJECTS.clock.getDelta(),

  init: () => {
    self = DRIVE
    actors = OBJECTS.actors
    groups = OBJECTS.groups
    materials = OBJECTS.materials
    textures = OBJECTS.textures
    lights = OBJECTS.lights

    // road = OBJECTS.curvepath
    // road = curveobject.geometry.parameters
    // delta = OBJECTS.delta;

    driveCurrentSpeed = FLAGS.driveCurrentSpeed
    driveAccelerationRate = FLAGS.driveAccelerationRate
    driveDeccelerationRate = FLAGS.driveDeccelerationRate
    driveMaxSpeed = FLAGS.driveMaxSpeed
    driveMinSpeed = FLAGS.driveMinSpeed

    car_follow = OBJECTS.car_follow
  },

  start: () => {
    if (DRIVE.ready) return

    OBJECTS.currentCamera = OBJECTS.cameras[2]

    self.setMaterials(true)
    self.setObjects(true)

    // removed set variable for progress_cam_rear and progress_car

    DRIVE.ready = true
  },

  end: () => {
    DRIVE.ready = false
  },

  setObjects: (start) => {
    if (start == true) {
      actors.pointer.visible = false
      actors.car_container.visible = true
    } else {
      actors.pointer.visible = true
      actors.car_container.visible = false
    }
  },

  setMaterials: (start) => {
    const road = OBJECTS.curveobject_drive
    const trails = OBJECTS.curvepath_extra

    const mtl = start ? materials.trail_drive : materials.trail_draw

    Object.values(trails).forEach((trail) => {
      trail.curveobject.material = mtl
    })

    if (start == true) {
      road.material = materials.trail_drive
      // road.material = materials.normalwire
      TweenMax.to($("#container"), 1, { backgroundColor: "#ffa500" })
      $("#header_logo").attr("class", "onblack")
    } else {
      road.material = materials.trail_draw
      // road.material = materials.normalwire

      TweenMax.to($("#container"), 1, { backgroundColor: "#ffa500" })
      $("#header_logo").attr("class", "onyellow")
    }
  },

  setTrail_Material: () => {},
  // 车子移动的核心函数
  moveCarAlongCurve: (speed) => {
    if (!OBJECTS.curvepath) return
    const curveobject = OBJECTS.curveobject_drive.geometry
    const path = OBJECTS.curvepath
    const time = Date.now()

    // let looptime = (path.points.length / 2) * 1000

    progress_car += speed
    progress_car = progress_car % 1

    let tpro = parseFloat(progress_car.toFixed(4)) * 100
    console.log(progress_car);

    //游戏结束的时候  hasover 结束标记
    if (Math.abs(tpro-99)<1 && !window.hasover) {
       window.hasover = true;
       console.log('Game Over');
       showPoster && showPoster();
    }

    $("#control_drive_button .before").css(
      "background",
      "conic-gradient(#000000 0, #000000 " +
        tpro +
        "%, #666666 " +
        (tpro + 0.01) +
        "%, #666666 100%)"
    )

    let t = progress_car

    const car = actors.car_container

    path.getPointAt(t, position)

    position.multiplyScalar(1)

    // interpolation
    const segments = curveobject.tangents.length
    // console.log(position);
    const pickt = t * segments
    const pick = Math.floor(pickt)
    const pickNext = (pick + 1) % segments

    // rough brute force lol

    // if (CONFIG.device == "android") {
    //   if (pickNext == 20) {
    //     navigator.vibrate(100);
    //   }

    //   switch (pickNext) {
    //     case 5:
    //       navigator.vibrate(100);
    //       break;
    //     case 10:
    //       navigator.vibrate(100);
    //       break;

    //     case 12:
    //       navigator.vibrate(300);
    //       break;

    //     case 17:
    //       navigator.vibrate(2000);
    //       break;

    //     case 30:
    //       navigator.vibrate(3000);
    //       break;

    //     case 36:
    //       navigator.vibrate(100);
    //       break;
    //     case 37:
    //       navigator.vibrate(100);
    //       break;

    //     case 40:
    //       navigator.vibrate(100);
    //       break;
    //     case 60:
    //       navigator.vibrate(5000);
    //       break;
    //   }
    // }

    binormal.subVectors(
      curveobject.binormals[pickNext],
      curveobject.binormals[pick]
    )

    binormal.multiplyScalar(pickt - pick).add(curveobject.binormals[pick])

    path.getTangentAt(t, direction)
    const offset = 0

    normal.copy(binormal).cross(direction)

    // we move on a offset on its binormal

    position.add(normal.clone().multiplyScalar(offset))
    car.position.copy(position)
    // cameraEye.position.copy(position)

    // using arclength for stablization in look ahead

    path.getPointAt((t + 10 / path.getLength()) % 1, car_LookAt)
    // car_LookAt.multiplyScalar(1)

    // camera orientation 2 - up orientation via normal
    // if (!params.lookAhead)car_.copy( position ).add( direction )

    car_LookAt.copy(position).add(direction) // disable if you want the car to drift

    car.matrix.lookAt(car.position, car_LookAt, normal)
    car.quaternion.setFromRotationMatrix(car.matrix)

    // actors.cam_rear.updateProj
  },
  // 车子后方摄像机移动的核心函数
  moveCameraAlongCurve: (speed) => {
    if (!OBJECTS.curvepath) return
    const curveobject = OBJECTS.curveobject_drive.geometry
    const path = OBJECTS.curvepath
    const delta = OBJECTS.delta
    const time = Date.now()

    // let looptime = (path.points.length / 2) * 1000
    progress_cam_rear += speed
    progress_cam_rear = progress_cam_rear % 1

    let t = progress_cam_rear

    const cam_rear = actors.cam_rear

    path.getPointAt(t, position)
    // console.log(path);
    // cam_rear.lookAt(car.position);

    // position.multiplyScalar(1)

    // interpolation
    // console.log(t,position);
    const segments = curveobject.tangents.length
    // 切片的数量是OBJECTS.curvepath_points.length（绘图路径点）*16，既路面渲染时的切片数量
    const pickt = t * segments
    const pick = Math.floor(pickt)
    const pickNext = (pick + 1) % segments

    binormal.subVectors(
      curveobject.binormals[pickNext],
      curveobject.binormals[pick]
    )

    binormal.multiplyScalar(pickt - pick).add(curveobject.binormals[pick])
    // console.log(t);
    path.getTangentAt(t, direction)
    const offset = 0

    // normal.copy(binormal).cross(direction);

    // we move on a offset on its binormal

    position.add(normal.clone().multiplyScalar(offset))
    cam_rear.position.copy(position)
    // cameraEye.position.copy(position)

    // using arclength for stablization in look ahead

    // 这里的t+4/path.getLength()是车后方摄像机lookAt的点，t后面的数字越小，lookAt的位置距离摄像机越近
    path.getPointAt((t + 4 / path.getLength()) % 1, cam_rear_LookAt)
    // cam_rear_LookAt.multiplyScalar(2)

    // camera orientation 2 - up orientation via normal
    // if (!params.lookAhead)
    // cam_rear_LookAt.copy(position).add(direction)
    cam_rear.matrix.lookAt(cam_rear.position, cam_rear_LookAt, normal)
    cam_rear.quaternion.setFromRotationMatrix(cam_rear.matrix)

    // actors.cam_rear.updateProj
    cam_rear.updateMatrixWorld()
  },

  drawAlongPath: () => {},

  steer: (delta) => {
    if (!DRIVE.ready) return
    if (!OBJECTS.arrowControl) return
    const control = OBJECTS.arrowControl
    const car = actors.car
    const gamma = control.deviceOrientation.gamma / 11.25
    // const gammaR = control.deviceOrientation.gamma / 5.625;
    const gammaR = control.deviceOrientation.gamma / 2.8125
    const steerMax = FLAGS.driveSteerMax
    // const steerMult = FLAGS.driveSteerMultiplier;

    let out = ""

    // switching lanes
    let clampedPosX = THREE.MathUtils.clamp(gamma, -steerMax, steerMax)
    let dampedPosX = THREE.MathUtils.damp(
      car.position.x,
      -clampedPosX,
      15,
      delta
    )

    // animate the speed lines / dash

    let clampedGamma = THREE.MathUtils.clamp(gammaR, -180, 180)

    car.position.x = dampedPosX
    car.rotation.y = (clampedGamma * Math.PI) / 180

    // get steer direction
    let dir = Math.sign(gamma)
    if (dir == 1) {
      textures.dash.offset.y += dir * gamma * 0.001
    } else {
      textures.dash.offset.y -= dir * gamma * 0.001
    }

    out += `
    gamma : ${gamma}<br/>
    `

    $("#debug").html(out)
  },
  // 加速逻辑
  handleAccelerate: () => {
    if (DRIVE.accelerate) {
      if (driveCurrentSpeed < driveMaxSpeed)
        driveCurrentSpeed += driveAccelerationRate * OBJECTS.delta
    } else {
      if (driveCurrentSpeed > driveMinSpeed) {
        driveCurrentSpeed -= driveDeccelerationRate * OBJECTS.delta
      } else {
        driveCurrentSpeed = driveMinSpeed
      } 
    }

    // deprecated, using single call to tween the material opacity to 1 and 0
    // // make the lines visible when the car accelerates
    // let alpha = TOOLS.remap(
    //   driveCurrentSpeed,
    //   driveMinSpeed,
    //   driveMaxSpeed,
    //   0,
    //   1
    // );
    // // clamp it
    // alpha = THREE.MathUtils.clamp(alpha,0,1);
    // materials.dash.opacity = alpha * 5;

    // $("#debug").html(`
    //  speed : ${alpha} <br/>
    //  `);
  },

  checkDistance_car: () => {
    const car = actors.car
    const cam_rear = actors.cam_rear

    let cam_worldPosition = cam_rear.getWorldPosition(new THREE.Vector3())
    let car_worldPosition = car.getWorldPosition(new THREE.Vector3())
    let distance = cam_worldPosition.distanceTo(car_worldPosition)

    return distance
  },

  haptic: () => {},

  tick: () => {
    const time = Date.now()

    // this value will make the camera move closer to the car at a set distance
    // declared in FLAGS.driveCameraDistanceFromCar in declarations.js
    let accelerationAdd = 0

    OBJECTS.delta = OBJECTS.clock.getDelta()

    if (driveCurrentSpeed > driveMinSpeed) {
    }

    if (DRIVE.ready) {
      if (DRIVE.checkDistance_car() > FLAGS.driveCameraDistanceFromCar) {
        accelerationAdd = 0.0001
      }

      DRIVE.steer(OBJECTS.delta)
      DRIVE.handleAccelerate(OBJECTS.delta)
       
      DRIVE.moveCarAlongCurve(driveCurrentSpeed )
      DRIVE.moveCameraAlongCurve(driveCurrentSpeed + accelerationAdd)
    }

    prevTime = time
  },
}

export { DRIVE };
